#include <kernel/kobject.h>
#include <kernel/initcall.h>
#include <kernel/syslog.h>
#include <mm/mem.h>
#include <drivers/simple.h>
#include <drivers/spi.h>
#include <stm32f10x_reg.h>


#define SPI_CR1_REG(io_base)           *(volatile uint32_t*)(io_base + 0x00)
#define SPI_CR2_REG(io_base)           *(volatile uint32_t*)(io_base + 0x04)
#define SPI_SR_REG(io_base)            *(volatile uint32_t*)(io_base + 0x08)
#define SPI_DR_REG(io_base)            *(volatile uint32_t*)(io_base + 0x0C)
#define SPI_CRCPR_REG(io_base)         *(volatile uint32_t*)(io_base + 0x10)
#define SPI_RXCRCR_REG(io_base)        *(volatile uint32_t*)(io_base + 0x14)
#define SPI_TXCRCR_REG(io_base)        *(volatile uint32_t*)(io_base + 0x18)
#define SPI_I2S_CFGR_REG(io_base)      *(volatile uint32_t*)(io_base + 0x1C)
#define SPI_I2SPR_REG(io_base)         *(volatile uint32_t*)(io_base + 0x20)



static int stm32f10x_spi_transfer(struct spi_device *spi, struct spi_transfer *xfer)
{
    
    return 0;
}


void stm32f10x_spi_set_cs(struct spi_device *spi, bool enable)
{
    struct spi_master *master = spi->master;
    uint32_t spi_base = (uint32_t)master->io_base;

    if(enable) {
        SPI_CR1_REG(spi_base) &= ~(1<<8);  //设置CS引脚低电平
    }
    else {
        SPI_CR1_REG(spi_base) |= (1<<8);  //设置CS引脚高电平
    }
}


void stm32f10x_spi_setup(struct spi_device *spi)
{
    struct spi_master *master = spi->master;
    uint32_t spi_base = (uint32_t)master->io_base;

    SPI_CR1_REG(spi_base) = 0x00;
    SPI_CR1_REG(spi_base) |= 0<<15; //选择“双线双向”模式

    if(spi->bits == 8) {
        SPI_CR1_REG(spi_base) |= 0<<11; //使用8位数据帧格式进行发送/接收；
    }
    else if(spi->bits == 16){
        SPI_CR1_REG(spi_base) |= 1<<11; //使用16位数据帧格式进行发送/接收；
    }

    SPI_CR1_REG(spi_base) |= 0<<10; //全双工(发送和接收)；
    SPI_CR1_REG(spi_base) |= 1<<9;  //开启CS引脚管理
    SPI_CR1_REG(spi_base) |= 1<<8;  //NSS，用于设置CS引脚电平
    SPI_CR1_REG(spi_base) |= 0<<7;  //帧格式，先发送高位
    SPI_CR1_REG(spi_base) |= 0x0<<3;//当总线频率为36MHZ时，SPI速度为18MHZ，高速。
    SPI_CR1_REG(spi_base) |= 1<<2;  //配置为主设备
    SPI_CR1_REG(spi_base) |= 1<<1;  //空闲状态时， SCK保持高电平。
    SPI_CR1_REG(spi_base) |= 1<<0;  //数据采样从第二个时钟边沿开始。
    SPI_CR1_REG(spi_base) |= 1<<6;  //开启SPI设备。
}


static int stm32f10x_spi_master_driver_probe(struct simple_device *dev)
{
    SYSLOG_INFO("probe ok %s", dev->platform_data);

    struct spi_master *master = kmalloc(sizeof(struct spi_master));
    if(master == NULL) {
        SYSLOG_ERROR("alloc spi master failed");
        return -1;
    }

    master->io_base = dev->io_base;
    master->transfer = stm32f10x_spi_transfer;
    master->set_cs = stm32f10x_spi_set_cs;
    master->setup = stm32f10x_spi_setup;

    return 0;
}


static void stm32f10x_spi_master_driver_remove(struct simple_device *dev)
{
    SYSLOG_INFO("remove ok %s", dev->platform_data);
}


static struct match_id stm32f10x_spi_master_match[] = {
    {.compatible = "stm32f103c8t6", },
    {.compatible = "stm32f103rct6", },
    { }
};


static struct simple_driver stm32f10x_spi_master_driver = {
    .probe = stm32f10x_spi_master_driver_probe,
    .remove = stm32f10x_spi_master_driver_remove,
    .id_table = stm32f10x_spi_master_match,
};


static int stm32f10x_spi_master_driver_register(void)
{
    simple_driver_register(&stm32f10x_spi_master_driver);
    return 0;
}


driver_initcall(stm32f10x_spi_master_driver_register);
